//
// Created by 无铭 on 25-3-12.
//

#ifndef JWTVALIDATIONSTRATEGY_HPP
#define JWTVALIDATIONSTRATEGY_HPP
#include "../Base64.h"
#include "Jwt.h"
#include "JwtDecoder.hpp"
#include <string>

namespace Utils
{
    class JwtValidationStrategy
    {
    public:
        virtual ~JwtValidationStrategy() = default;

        // 验证签名策略
        virtual Jwt::ValidationResult
        validate_signature(const JwtDecodeResult &decoded,
                           const std::string &secret_key) const = 0;

        // 验证业务逻辑策略
        virtual Jwt::ValidationResult
        validate_claims(const JwtDecodeResult &decoded) const = 0;
    };

    class HS256ValidationStrategy : public JwtValidationStrategy
    {
        // 验证签名策略
        Jwt::ValidationResult
        validate_signature(const JwtDecodeResult &decoded,
                           const std::string &secret_key) const override
        {
            const auto data = decoded.header_b64 + "." + decoded.payload_b64;
            const auto expected_sig = hmac_sha256(secret_key, data);
            if (base64url_encode(expected_sig) != decoded.signature_b64)
            {
                return Jwt::ValidationResult::NotMatched;
            }
            return Jwt::ValidationResult::Valid;
        }

        // 验证业务逻辑策略
        Jwt::ValidationResult
        validate_claims(const JwtDecodeResult &decoded) const override
        {
            auto now = std::chrono::system_clock::now();
            auto timeStamp = std::chrono::duration_cast<std::chrono::seconds>(
                        now.time_since_epoch())
                    .count();
            const uint64_t iat = decoded.payload_json["iat"];
            const uint64_t exp = decoded.payload_json["exp"];

            if (timeStamp > iat + exp)
            {
                return Jwt::ValidationResult::Expired;
            }
            return Jwt::ValidationResult::Valid;
        }

    private:
        static std::string hmac_sha256(const std::string &secret_key,
                                       const std::string &data)
        {
            const auto expected_sig = Encrypter::hmac_sha256(secret_key, data);
            return expected_sig;
        }

        static std::string base64url_encode(const std::string &input)
        {
            Base64 base64;
            return base64.url_encode(input);
        }
    };
} // namespace Utils
#endif // JWTVALIDATIONSTRATEGY_HPP
